#include "radix.h"


#ifndef _USE_ISOC99B
#define __func__ "Your_compiler_did_not_support_C99"
#endif


#ifdef ENABLE_EVMAP_DEBUG_PASS
static int debug_times = 1;
#endif

// #define DEFAULT_RADIX_CONFIG {0, 32, 100000, 80}

#define DEFAULT_WITHOUTLOCK  (int32_t)0
#define DEFAULT_TREEDEEP     (int32_t)32
#define DEFAULT_MAXLEAF      (int32_t)100000
#define DEFAULT_LRYPERCENT   (int32_t)80

static inline void radix_debug_pass(char *file, char *func, int line)
{
#ifdef ENABLE_EVMAP_DEBUG_PASS
    printf("File: %s\n"
           "Func: %s()\n"
           "Line: %d\n"
           "Pass %d\n\n", file, func, line, debug_times);
    debug_times++;    
#endif
}


// struct radixNode;

// struct radixConfig{
//     int32_t  withLock ;
//     int32_t  treeDeep ;
//     int32_t  maxLeafNode  ;
//     int32_t  lruPercent   ;
//     int32_t  maxDeep      ;
// };

// struct radixNode{
//     void   *data;
//     struct radixNode * left  ;
//     struct radixNode * right ;
//     int16_t  nodeDeep        ;
//     int16_t  uniqueFlag      ;
//     uint32_t viewCount       ;
// };

// struct radixTree{
//     struct radixNode    *root   ;
//     struct radixNode    *lruHead;
//     uint32_t            numNode ;
//     LOCK                *lock   ;
//     struct radixConfig  *rconfig;
// };


static int bitMap[MAXRADIXDEEP] ;

static int32_t globalInit(){
    int i = 0 ;
    for(; i < MAXRADIXDEEP; i++){
        bitMap[i] = 1;
    }
}


static inline struct radixNode * radixGetNode(){
    struct radixNode *retNode = (struct radixNode *)malloc(sizeof(struct radixNode));
    if(retNode == (struct radixNode *)NULL){
        return (struct radixNode*)NULL;
    }
    retNode->data  = (void *)NULL);
    retNode->left  = (struct radixNode *)NULL ;
    retNode->right = (struct radixNode *)NULL ;
    retNode->nodeDeep   = 0;
    retNode->uniqueFlag = 0;
    retNode->viewCount  = 0;
    return (struct radixNode *)retNode ;
}


static inline int32_t checkTree(radixTree * _t)
{
    if ( _t == (radixTree *)NULL ){
        return -1;
    }
    return 0;
}


static inline int32_t radixCreateLock(radixTree * _t)
{
    if( checkTree(_t) == -1){
        return -1;
    }
    if( _t->lock == (pthread_mutex_t *)NULL ){
        _t->lock = radixAlloc(sizeof(pthread_mutex_t)) ;
        if (_t->lock == (pthread_mutex_t *)NULL){
            return -1;
        }
    }
    pthread_mutex_init(_t->lock);
    return 0;
}


int32_t radixLock(radixTree * _t)
{
    return pthread_mutex_lock(_t->lock);
}


int32_t radixUnlock(radixTree * _t)
{
    return pthread_mutex_unlock(_t->lock);
}


int32_t radixCreate(radixTree * _t, radixConfig * _rconfig)
{
    if (checkTree(_t) == -1){
        return -1;
    }

    radixConfig *lc = _t->rconfig;
    if ( lc == (struct radixConfig *)NULL ){
        lc = (struct radixConfig *)radixAlloc(sizeof(struct radixConfig));
    }

    if ( _rconfig == (radixConfig *)NULL){
        lc->withLock    = DEFAULT_WITHOUTLOCK ;
        lc->treeDeep    = DEFAULT_TREEDEEP    ;
        lc->maxLeafNode = DEFAULT_MAXLEAF     ;
        lc->lruPercent  = DEFAULT_LRYPERCENT  ;
    }

    _t->root = (struct radixNode *)radixAlloc(sizeof(struct radixNode));
    if (_t->root == (struct radixNode *)NULL){
        radix_debug_pass(__FILE__, "radix.c/radixCreate", __LINE__);
        if (lc){
            radixFree(lc);
        }
        return -1;
    }

    // init root
    _t->root->data  = (void *)NULL);
    _t->root->left  = (struct radixNode *)NULL ;
    _t->root->right = (struct radixNode *)NULL ;
    _t->root->nodeDeep   = 0;
    _t->root->uniqueFlag = 0;

    _t->numNode = 0;
    
    // init lock
    if(lc->withLock == DEFAULT_WITHOUTLOCK){
        _t->lock = NULL;
    }else if (radixCreateLock(_t) == -1){
        return -1;
    }

    return 0;
}


int32_t radixInsert(radixTree * _t, uint32_t _key, void * _value, uint32_t _dataLength)
{
    if(    checkTree(_t) == 0     \
        || _value == (void *)NULL \
        || _dataLength == 0)
    {
        return -1;
    }

    radixTree * rt = _t->root;
    uint32_t deep = _t->rconfig->maxDeep > MAXRADIXDEEP ? 32 : MAXRADIXDEEP ;
    uint32_t localUnique =  _key;

    //left or right
    int lr = -1;
    while(deep--){
        rt->viewCount++;

        lr = (localUnique >> deep)&bitMap[deep] ;
        if(lr){
            if(rt->left){
                rt = rt->left;
            }else{
                rt->left = radixGetNode();
                if(!rt->left) goto err;
            }
        }else{
            if(rt->right){
                rt = rt->right;
            }else{
                rt->right = radixGetNode();
                if(!rt->right) goto err;
            }
        }
        rt->nodeDeep = deep ;
    }

    if(rt->data) {
        free(rt->data);
    }
    rt->data = malloc(_dataLength);
    if(!rt->data){
        goto err;
    }

    memcpy(rt->data, _value, _dataLength);
    _t->numNode++;

    //add to lru list

    return 0;
err:
    return -1;
}

int32_t radixDestory(radixTree * _t){
    return -1;
}


int32_t radixDel(radixTree * _t, uint32_t _key){
    return -1;
}


int32_t radixLRU(radixTree * _t, int32_t  lruPercent){
    return -1;
}


int32_t radixInfo(radixTree * _t){
    return -1;
}
